home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / formats / iff / newiff.lzh / NewIFF / NewIFF.lzh / newiff / modules / parse.c < prev    next >
C/C++ Source or Header  |  1992-05-18  |  10KB  |  440 lines

  1. /*  
  2.  * parse.c - iffparse file IO support module
  3.  *   based on some of looki.c by Leo Schwab
  4.  *
  5.  * The filename for clipboard is -c or -cUnit as in -c0 -c1 etc. (default 0)
  6.  */
  7.  
  8. #include <exec/types.h>
  9.  
  10. #include "iffp/iff.h"
  11.  
  12. /* local function prototypes */
  13.  
  14. static LONG stdio_stream(struct Hook *, struct IFFHandle *, struct IFFStreamCmd *);
  15.  
  16. UBYTE *omodes[2] = {"r","w"};
  17.  
  18.  
  19. /* openifile
  20.  *
  21.  * Passed a ParseInfo structure with a not-in-use IFFHandle, filename
  22.  *   ("-c" or -cUnit like "-c1" for clipboard), and IFF open mode
  23.  *   (IFFF_READ or IFFF_WRITE) opens file or clipboard for use with
  24.  *   iffparse.library support modules.
  25.  *
  26.  * Returns 0 for success or an IFFERR (libraries/iffparse.h)
  27.  */
  28.  
  29. LONG openifile(struct ParseInfo *pi, UBYTE *filename, ULONG iffopenmode)
  30. {
  31.     struct IFFHandle    *iff;
  32.     BOOL    cboard;
  33.     ULONG     unit = PRIMARY_CLIP;
  34.     LONG     error;
  35.  
  36.     if(!pi)            return(CLIENT_ERROR);
  37.         if(!(iff=pi->iff))    return(CLIENT_ERROR);
  38.  
  39.     cboard = (*filename == '-'  &&  filename[1] == 'c');
  40.      if(cboard && filename[2])    unit = atoi(&filename[2]);
  41.  
  42.     if (cboard)
  43.         {
  44.         /*
  45.          * Set up IFFHandle for Clipboard I/O.
  46.          */
  47.         pi->clipboard = TRUE;
  48.         if (!(iff->iff_Stream =
  49.                 (ULONG)OpenClipboard(unit)))
  50.             {
  51.             message(SI(MSG_IFFP_NOCLIP_D),unit);
  52.             return(NOFILE);
  53.             }
  54.         InitIFFasClip(iff);
  55.         }
  56.     else
  57.         {
  58.         pi->clipboard = FALSE;
  59.         /*
  60.          * Set up IFFHandle for buffered stdio I/O.
  61.          */
  62.         if (!(iff->iff_Stream = (ULONG)
  63.            fopen(filename, omodes[iffopenmode & 1])))
  64.             {
  65.             message(SI(MSG_IFFP_NOFILE_S),filename);
  66.             return(NOFILE);
  67.             }
  68.         else initiffasstdio(iff);
  69.         }
  70.  
  71.     D(bug("%s file opened: \n", cboard ? "[Clipboard]" : filename));
  72.  
  73.     pi->filename = filename;
  74.  
  75.     error=OpenIFF(iff, iffopenmode);
  76.  
  77.     pi->opened = error ? FALSE : TRUE;    /* currently open handle */
  78.  
  79.     D(bug("OpenIFF error = %ld\n",error));
  80.     return(error);
  81. }
  82.  
  83.  
  84. /* closeifile
  85.  *
  86.  * closes file or clipboard opened with openifile, and frees all
  87.  *   iffparse context parsed by parseifile.
  88.  *
  89.  * Note - You should closeifile as soon as possible if using clipboard
  90.  *   ("-c[n]").  You also need to closeifile if, for example, you wish to
  91.  *   reopen the file to write changes back out.  See the copychunks.c
  92.  *   module for routines which allow you clone the chunks iffparse has
  93.  *   gathered so that you can closeifile and still be able to modify and
  94.  *   write back out gathered chunks.
  95.  *   
  96.  */
  97.  
  98. void closeifile(struct ParseInfo *pi)
  99. {
  100. struct IFFHandle *iff;
  101.  
  102.     D(bug("closeifile:\n"));
  103.  
  104.     if(!pi)            return;
  105.         if(!(iff=pi->iff))    return;
  106.  
  107.     DD(bug("closeifile: About to CloseIFF if open, iff=$%lx, opened=%ld\n",
  108.             iff, pi->opened));
  109.  
  110.     if(pi->opened)    CloseIFF(iff);
  111.  
  112.     DD(bug("closeifile: About to close %s, stream=$%lx\n",
  113.             pi->clipboard ? "clipboard" : "file", iff->iff_Stream));
  114.     if(iff->iff_Stream)
  115.         {
  116.         if (pi->clipboard)
  117.            CloseClipboard((struct ClipHandle *)(iff->iff_Stream));
  118.         else
  119.            fclose ((FILE *)(iff->iff_Stream));
  120.         }
  121.  
  122.     iff->iff_Stream = NULL;
  123.     pi->clipboard = NULL;
  124.     pi->opened = NULL;
  125. }
  126.  
  127.  
  128. /* parseifile
  129.  *
  130.  * Passed a ParseInfo with an initialized and open IFFHandle,
  131.  *  grouptype (like ID_FORM), groupid (like ID_ILBM),
  132.  *  and TAG_DONE terminated longword arrays of type,id
  133.  *  for chunks to be grabbed, gathered, and stopped on
  134.  *  (like { ID_ILBM, ID_BMHD, ID_ILBM, ID_CAMG, TAG_DONE })
  135.  *  will parse an IFF file, grabbing/gathering and stopping
  136.  *  on specified chunk.
  137.  *
  138.  * Note - you can call getcontext() (to continue after a stop chunk) or
  139.  *  nextcontext() (after IFFERR_EOC, to parse next form in the same file)
  140.  *  if you wish to continue parsing the same IFF file.  If parseifile()
  141.  *  has to delve into a complex format to find your desired FORM, the
  142.  *  pi->hunt flag will be set.  This should be a signal to you that
  143.  *  you may not have the capability to simply modify and rewrite
  144.  *  the data you have gathered.
  145.  *
  146.  * Returns 0 for success else and IFFERR (libraries/iffparse.h)
  147.  */ 
  148.  
  149. LONG parseifile(pi,groupid,grouptype,propchks,collectchks,stopchks)
  150. struct    ParseInfo *pi;
  151. LONG groupid, grouptype;
  152. LONG *propchks, *collectchks, *stopchks;
  153. {
  154. struct IFFHandle *iff;    
  155. register struct ContextNode    *cn;
  156. LONG            error = 0L;
  157.  
  158.  
  159.         if(!(iff=pi->iff))    return(CLIENT_ERROR);
  160.  
  161.     if(!iff->iff_Stream)    return(IFFERR_READ);
  162.  
  163.     pi->hunt = FALSE;
  164.  
  165.     /*
  166.      * Declare property, collection and stop chunks.
  167.      */
  168.     if (propchks)
  169.       if (error = PropChunks (iff, propchks, chkcnt(propchks)))
  170.         return (error);
  171.     if (collectchks)
  172.       if (error =
  173.           CollectionChunks(iff, collectchks, chkcnt(collectchks)))
  174.         return (error);
  175.     if (stopchks)
  176.       if (error = StopChunks (iff, stopchks, chkcnt(stopchks)))
  177.         return (error);
  178.  
  179.     /*
  180.      * We want to stop at the end of an ILBM context.
  181.      */
  182.     if (grouptype)
  183.       if (error = StopOnExit (iff, grouptype, groupid))
  184.         return(error);
  185.  
  186.     /*
  187.      * Take first parse step to enter main chunk.
  188.      */
  189.     if (error = ParseIFF (iff, IFFPARSE_STEP))
  190.         return(error);
  191.  
  192.     /*
  193.      * Test the chunk info to see if simple form of type we want (ILBM).
  194.      */
  195.     if (!(cn = CurrentChunk (iff)))
  196.         {
  197.         /*
  198.          * This really should never happen.  If it does, it means
  199.          * our parser is broken.
  200.          */
  201.         message(SI(MSG_IFFP_NOTOP));
  202.         return(NOFILE);
  203.         }
  204.  
  205.     if (cn->cn_ID != groupid  ||  cn->cn_Type != grouptype)
  206.         {
  207.         
  208.         D(bug("This is a(n) %.4s.%.4s.  Looking for embedded %.4s's...\n",
  209.           &cn->cn_Type, &cn->cn_ID, &grouptype));
  210.  
  211.         pi->hunt = TRUE;    /* Warning - this is a complex file */
  212.         }
  213.  
  214.     if(!error)    error = getcontext(iff);
  215.     return(error);
  216. }
  217.  
  218. /* chkcnt
  219.  *
  220.  * simply counts the number of chunk pairs (type,id) in array
  221.  */
  222. LONG chkcnt(LONG *taggedarray)
  223. {
  224. LONG k = 0;
  225.  
  226.     while(taggedarray[k] != TAG_DONE) k++;
  227.     return(k>>1);
  228. }
  229.  
  230.  
  231. /* currentchunkis
  232.  *
  233.  * returns the ID of the current chunk (like ID_CAMG)
  234.  */
  235. LONG currentchunkis(struct IFFHandle *iff, LONG type, LONG id)
  236. {
  237. register struct ContextNode    *cn;
  238. LONG result = 0;
  239.  
  240.     if (cn = CurrentChunk (iff))
  241.         {
  242.         if((cn->cn_Type == type)&&(cn->cn_ID == id)) result = 1;
  243.         }
  244.     return(result);
  245. }
  246.  
  247.  
  248. /* contextis
  249.  *
  250.  * returns the enclosing context of the current chunk (like ID_ILBM)
  251.  */
  252. LONG contextis(struct IFFHandle *iff, LONG type, LONG id)
  253. {
  254. register struct ContextNode    *cn;
  255. LONG result = 0;
  256.  
  257.        if (cn = (CurrentChunk (iff)))
  258.            {
  259.            if (cn = (ParentChunk(cn)))
  260.                {
  261.                if((cn->cn_Type == type)&&(cn->cn_ID == id)) result = 1;
  262.                }
  263.        }
  264.  
  265.     D(bug("This is a %.4s %.4s\n",&cn->cn_Type,&cn->cn_ID));
  266.  
  267.     return(result);
  268. }
  269.  
  270.  
  271. /* getcontext()
  272.  *
  273.  * Continues to gather the context which was specified to parseifile(),
  274.  *  stopping at specified stop chunk, or end of context, or EOF
  275.  *
  276.  * Returns 0 (stopped on a stop chunk)
  277.  *      or IFFERR_EOC (end of context, not an error)
  278.  *      or IFFER_EOF (end of file)
  279.  */
  280. LONG getcontext(iff)
  281. struct    IFFHandle *iff;
  282. {
  283.     LONG error = 0L;
  284.  
  285.     /* Based on our parse initialization,
  286.      * ParseIFF() will return on a stop chunk (error = 0)
  287.      * or end of context for an ILBM FORM (error = IFFERR_EOC)
  288.      * or end of file (error = IFFERR_EOF)
  289.      */
  290.     return(error = ParseIFF(iff, IFFPARSE_SCAN));
  291. }
  292.  
  293.  
  294. /* nextcontext
  295.  *
  296.  * If you have finished parsing and reading your context (IFFERR_EOC),
  297.  *   nextcontext will enter the next context contained in the file
  298.  *   and parse it.
  299.  *
  300.  * Returns 0 or an IFFERR such as IFFERR_EOF (end of file)
  301.  */
  302.  
  303. LONG nextcontext(iff)
  304. struct    IFFHandle *iff;
  305. {
  306.     LONG error = 0L;
  307.  
  308.     error = ParseIFF(iff, IFFPARSE_STEP);
  309.  
  310.     D(bug("nextcontext: Got through next step\n"));
  311.  
  312.     return(error);
  313. }
  314.  
  315.  
  316. /* findpropdata
  317.  *
  318.  * finds specified chunk parsed from IFF file, and
  319.  *   returns pointer to its sp_Data (or 0 for not found)
  320.  */
  321. UBYTE *findpropdata(iff, type, id)
  322. struct IFFHandle    *iff;
  323. LONG type, id;
  324.     {
  325.     register struct StoredProperty    *sp;
  326.  
  327.     if(sp = FindProp (iff, type, id)) return(sp->sp_Data);
  328.     return(0);
  329.     }
  330.  
  331.  
  332. /*
  333.  * File I/O hook functions which the IFF library will call.
  334.  * A return of 0 indicates success (no error).
  335.  *
  336.  * Iffparse.library calls this code via struct Hook and Hook.asm
  337.  */
  338. static LONG
  339. stdio_stream (struct Hook *hook, struct IFFHandle *iff,
  340.             struct IFFStreamCmd *actionpkt)
  341. {
  342.     register FILE    *stream;
  343.     register LONG    nbytes;
  344.     register int    actual;
  345.     register UBYTE    *buf;
  346.     long    len;
  347.  
  348.     stream    = (FILE *) iff->iff_Stream;
  349.     if(!stream)    return(1);
  350.  
  351.     nbytes    = actionpkt->sc_NBytes;
  352.     buf    = (UBYTE *) actionpkt->sc_Buf;
  353.  
  354.     switch (actionpkt->sc_Command) {
  355.     case IFFSCC_READ:
  356.         do {
  357.             actual = nbytes > 32767 ? 32767 : nbytes;
  358.             if ((len=fread (buf, 1, actual, stream)) != actual)
  359.                 break;
  360.             nbytes -= actual;
  361.             buf += actual;
  362.         } while (nbytes > 0);
  363.         return (nbytes ? IFFERR_READ : 0 );
  364.  
  365.     case IFFSCC_WRITE:
  366.         do {
  367.             actual = nbytes > 32767 ? 32767 : nbytes;
  368.             if ((len=fwrite (buf, 1, actual, stream)) != actual)
  369.                 break;
  370.             nbytes -= actual;
  371.             buf += actual;
  372.         } while (nbytes > 0);
  373.         return (nbytes ? IFFERR_WRITE : 0);
  374.  
  375.     case IFFSCC_SEEK:
  376.         return ((fseek (stream, nbytes, 1) == -1) ? IFFERR_SEEK : 0);
  377.  
  378.     default:
  379.         /*  No _INIT or _CLEANUP required.  */
  380.         return (0);
  381.     }
  382. }
  383.  
  384. /* initiffasstdio (ie. init iff as stdio)
  385.  *
  386.  * sets up hook callback for the file stream handler above
  387.  */
  388. void initiffasstdio (iff)
  389. struct IFFHandle *iff;
  390. {
  391.     extern LONG        HookEntry();
  392.     static struct Hook    stdiohook = {
  393.         { NULL },
  394.         (ULONG (*)()) HookEntry,
  395.         (ULONG (*)()) stdio_stream,
  396.         NULL
  397.     };
  398.  
  399.     /*
  400.      * Initialize the IFF structure to point to the buffered I/O
  401.      * routines.  Unbuffered I/O is terribly slow.
  402.      */
  403.     InitIFF (iff, IFFF_FSEEK | IFFF_RSEEK, &stdiohook);
  404. }
  405.  
  406.  
  407. /*
  408.  * PutCk
  409.  *
  410.  * Writes one chunk of data to an iffhandle
  411.  *
  412.  */
  413. long PutCk(struct IFFHandle *iff, long id, long size, void *data)
  414.     {
  415.     long error = 0, wlen;
  416.  
  417.     D(bug("PutCk: asked to push chunk \"%.4s\" ($%lx) length %ld\n",&id,id,size));
  418.  
  419.     if(error=PushChunk(iff, 0, id, size))
  420.     {
  421.     D(bug("PutCk: PushChunk of %.4s, error = %s, size = %ld\n",
  422.         id, IFFerr(error), id));
  423.     }
  424.     else
  425.     {
  426.     D(bug("PutCk: PushChunk of %.4s, error = %ld\n",&id, error));
  427.  
  428.     /* Write the actual data */
  429.     if((wlen = WriteChunkBytes(iff,data,size)) != size)
  430.         {
  431.         D(bug("WriteChunkBytes error: size = %ld, wrote %ld\n",size,wlen));
  432.         error = IFFERR_WRITE;
  433.         }
  434.     else error = PopChunk(iff);
  435.     D(bug("PutCk: After PopChunk - error = %ld\n",error));
  436.     }
  437.     return(error);
  438.     }
  439.  
  440.